home *** CD-ROM | disk | FTP | other *** search
- TITLE XYCLIP - SUTHERLAND-HODGEMAN CLIPPER IN ASSEMBLER
-
- COMMENT $
-
- // 26/12/93 by Dave Stampe
- // All algorithms and code (c) 1993 by Dave Stampe
-
- /*
- This code is part of the REND386 project, created by Dave Stampe and
- Bernie Roehl.
-
- Copyright 1992, 1993, 1994 by Dave Stampe and Bernie Roehl.
-
- May be freely used to write software for release into the public domain;
- all commercial endeavours MUST contact BOTH Bernie Roehl and Dave Stampe
- for permission to incorporate any part of this software into their
- products! Usually there is no charge for under 50-100 items for
- low-cost or shareware, and terms are reasonable. Any royalties are used
- for development, so equipment is often acceptable payment.
-
- ATTRIBUTION: If you use any part of this source code or the libraries
- in your projects, you must give attribution to REND386, Dave Stampe,
- and Bernie Roehl in your documentation, source code, and at startup
- of your program. Let's keep the freeware ball rolling! No more
- code ripoffs please.
-
- CONTACTS: dstampe@psych.toronto.edu, broehl@sunee.uwaterloo.ca
- See the COPYRITE.H file for more information.
- */
-
- This is a reasonably efficient semi-recursive XY screen clipper
- for polygons. XY_clip_array() is the C call, which takes an array of
- (NVERTEX *) and processes to an output array. New clipped vertices
- may be produced: old vertices are not discarded.
-
-
- /* Contact: dstampe@sunee.waterloo.edu */
-
- $
-
- .MODEL large
- .386
-
-
- .DATA
-
- include 3dstruct.inc
- include viewdata.inc
-
- ; clipper record variables
-
- first_top_vtx dd 0 ; for each level: record first, and latest vertex
- last_top_vtx dd 0
-
- first_bottom_vtx dd 0
- last_bottom_vtx dd 0
-
- first_left_vtx dd 0
- last_left_vtx dd 0
-
- first_right_vtx dd 0
- last_right_vtx dd 0
-
- destptr dd 0 ; where to put output
- vtxcount dw 0 ; vertex passed count
-
- include rendmem.inc
-
- .CODE RENDERER
-
- ; defined in RENDMEM.INC
- ; alloc new vertex
- ; returns new vertex in ES:BX
- ; BX only affected
-
- ;ALLOCVTX MACRO
- ; les bx,_nvalloc
- ; sub bx, SIZE NVERTEX
- ; mov _nvalloc,bx
- ; mov WORD PTR es:[bx].NV_persp,0
- ; ENDM
-
-
-
- ;/********** CREATE NEW INTERCEPT VERTEX **************/
-
- ; static NVERTEX *y_intercept(NVERTEX *v1, NVERTEX *v2, long edge)
- ; static NVERTEX *x_intercept(NVERTEX *v1, NVERTEX *v2, long edge)
-
- ; ARGUMENTS:
-
- ; v1: ES:SI
- ; v2: ES:DI
- ; edge: ecx
- ; new, return: ES:BX
-
- ; MAKES ASSUMPTION THAT ALL
- x1 equ DWORD PTR es:[di].NV_xs ; NVERTEX ARE IN SAME SEGMENT
- y1 equ DWORD PTR es:[di].NV_ys
- z1 equ DWORD PTR es:[di].NV_z ; vtx 1
-
- x2 equ DWORD PTR es:[si].NV_xs ; vtx 2
- y2 equ DWORD PTR es:[si].NV_ys
- z2 equ DWORD PTR es:[si].NV_z
-
- xn equ DWORD PTR es:[bx].NV_xs ; intercept
- yn equ DWORD PTR es:[bx].NV_ys
- zn equ DWORD PTR es:[bx].NV_z
-
-
- y_intercept proc near
-
- ALLOCVTX ; es:bx is new vertex, assume es is renderer temp
-
- mov yn,ecx
- mov ecx,y1
- sub ecx,y2
- jl fwd_clip_y ; clip from high end to prevent roundoff
- jg rev_clip_y
-
- mov eax,x1 ; no slope: copy vtx 1
- mov xn,eax
- mov eax,z1
- mov zn,eax
- ret
-
- rev_clip_y:
- mov eax,yn ; compute new z
- sub eax,y2
- mov edx,z1
- sub edx,z2
- imul edx
- idiv ecx
- add eax,z2
- mov zn,eax
-
- mov eax,yn ; compute new x
- sub eax,y2
- mov edx,x1
- sub edx,x2
- imul edx
- idiv ecx
- add eax,x2
- mov xn,eax
- ret
-
- fwd_clip_y:
- neg ecx
-
- mov eax,yn ; compute new z
- sub eax,y1
- mov edx,z2
- sub edx,z1
- imul edx
- idiv ecx
- add eax,z1
- mov zn,eax
-
- mov eax,yn ; compute new x
- sub eax,y1
- mov edx,x2
- sub edx,x1
- imul edx
- idiv ecx
- add eax,x1
- mov xn,eax
- ret
-
- y_intercept endp
-
-
-
- x_intercept proc near
-
- ALLOCVTX ; es:bx is new vertex, assume es is renderer temp
-
- mov xn,ecx
- mov ecx,x1
- sub ecx,x2
- jl fwd_clip_x ; clip from high end to prevent roundoff
- jg rev_clip_x
-
- mov eax,y1 ; no slope: copy vtx 1
- mov yn,eax
- mov eax,z1
- mov zn,eax
- ret
-
- rev_clip_x:
- mov eax,xn ; compute new z
- sub eax,x2
- mov edx,z1
- sub edx,z2
- imul edx
- idiv ecx
- add eax,z2
- mov zn,eax
-
- mov eax,xn ; compute new y
- sub eax,x2
- mov edx,y1
- sub edx,y2
- imul edx
- idiv ecx
- add eax,y2
- mov yn,eax
- ret
-
- fwd_clip_x:
- neg ecx
-
- mov eax,xn ; compute new z
- sub eax,x1
- mov edx,z2
- sub edx,z1
- imul edx
- idiv ecx
- add eax,z1
- mov zn,eax
-
- mov eax,xn ; compute new y
- sub eax,x1
- mov edx,y2
- sub edx,y1
- imul edx
- idiv ecx
- add eax,y1
- mov yn,eax
- ret
-
- x_intercept endp
-
-
-
- ;/************* CLIPPER C INTERFACE **********/
-
- ; XY clip an array of vertices, store in array
- ; returns number of vertices produced
- ;
- ; int XY_clip_array(NVERTEX **src, NVERTEX **dest, int count);
-
- src equ DWORD PTR [bp+8] ; arguments
- dest equ DWORD PTR [bp+12]
- count equ WORD PTR [bp+16]
-
- srcptr equ DWORD PTR [bp-4] ; locals
- n equ WORD PTR [bp-8] ; vertex counter
-
-
- ;CHECKMEM MACRO num_vertex ;; DEFINED IN RENDMEM.INC
- ; mov ax,num_vertex
- ; imul ax,SIZE NVERTEX
- ; add ax,200
- ; add ax,WORD PTR _npalloc
- ; neg ax
- ; add ax,WORD PTR _nvalloc ; carry clear if out of memory
- ; ENDM
-
-
- PUBLIC _XY_clip_array
-
- _XY_clip_array proc far
-
- push ebp
- mov ebp,esp
- sub esp,16
-
- push esi
- push edi
- push ecx
- push edx
-
- mov last_top_vtx,0 ; reset clipper variables
- mov last_bottom_vtx,0
- mov last_left_vtx,0
- mov last_right_vtx,0
- mov vtxcount,0
-
- mov eax,src
- mov srcptr,eax
- mov eax,dest
- mov destptr,eax
- mov ax,count
- mov n,ax
- ; enough mem for all vtxs?
- CHECKMEM 10
- jc have_memory
- mov vtxcount,-1
- jmp exit_clip
-
- have_memory:
- next_clip:
- mov ax,OTOP ; call top level of clipper
- push ax
- les bx,srcptr
- mov eax,es:[bx]
- push eax
- call near ptr XY_clip
- add esp,6
-
- add srcptr,4
- dec n
- jne next_clip
-
- cmp count,2
- jle exit_clip
-
- mov ax,OTOP ; flush clipper
- push ax
- xor eax,eax
- push eax
- call near ptr XY_clip
- add esp,6
-
-
- exit_clip:
- mov ax,vtxcount
-
- pop edx
- pop ecx
- pop edi
- pop esi
-
- mov esp,ebp
- pop ebp
- ret
-
- _XY_clip_array endp
-
-
-
-
- ;/************ RECURSIVE CLIPPER KERNAL *************/
-
- ;static void XY_clip(NVERTEX *vtx, int stage)
- ; /* XY semirecursive clipper */
- ; /* set last = NULL before first call */
- ; /* call with all (copied) vertices */
- ; /* call with NULL to flush */
- ; /* also copies output to poly table */
-
- vtx equ DWORD PTR [bp+6] ; arguments
- stage equ WORD PTR [bp+10] ; FOR NEAR CALL OFFSETS
-
- XY_clip proc near
-
- push ebp ; generic entry
- mov ebp,esp
-
- mov ax,stage ; find stage
- cmp ax,OTOP
- je top_clip
- cmp ax,ORIGHT
- je right_clip
- cmp ax,OBOTTOM
- je bottom_clip
- jmp left_clip
-
- XY_clip_bottom: ; fast local entries
- push ebp
- mov ebp,esp
- jmp bottom_clip
-
- XY_clip_left:
- push ebp
- mov ebp,esp
- jmp left_clip
-
- XY_clip_right:
- push ebp
- mov ebp,esp
- jmp right_clip
-
- XY_clip_top:
- push ebp
- mov ebp,esp
-
-
- ;;;;;;;; START OF TOP CLIP;;;;;;;;;;;
-
- top_clip:
- mov eax,DWORD PTR last_top_vtx ; is this the first?
- or eax,eax
- jnz not_first_top
-
- or eax,vtx ; traps NULL if first=last
- je right_clip
- mov last_top_vtx,eax ; record
- mov first_top_vtx,eax
- les bx,vtx
- mov al,BYTE PTR es:[bx].NV_ocode ; pass if in window
- test al,OTOP ; we can use outcode on first only
- jnz end_XY_clip
- jmp right_clip
-
- not_first_top: ; OK, we've got an edge
- mov eax,DWORD PTR vtx
- or eax,eax
- jnz not_flush_top ; NULL to flush clipper
-
- les si,first_top_vtx ; look for window top crossing
- mov al,BYTE PTR es:[si].NV_ocode
- les di,last_top_vtx
- xor al,BYTE PTR es:[di].NV_ocode
- test al,OTOP
- jz right_clip
-
- ; nv = y_intercept(first_top_vtx, last_top_vtx, VS_top4);
- ; XY_clip(nv,RIGHT); /* process this new point */
-
- mov ecx,_VS_top4 ; si,di,es already loaded
- call y_intercept ; create intercept vertex
- push es
- push bx
- call near ptr XY_clip_right ; and clip it
- add esp,4
- jmp right_clip ; continue to flush
-
- not_flush_top:
- les si,vtx
- mov al,BYTE PTR es:[si].NV_ocode
- push ax
- les di,last_top_vtx
- xor al,BYTE PTR es:[di].NV_ocode
- test al,OTOP
- jz do_top_clip
-
- mov ecx,_VS_top4 ; si,di,es already loaded
- call y_intercept ; create intercept vertex
- push es
- push bx ; and clip it
- call near ptr XY_clip_right
- add esp,4 ; continue with original vertex
-
- do_top_clip:
- mov eax,vtx ; ave as last vertex
- mov last_top_vtx,eax
- pop ax
- test al,OTOP ; was vertex in window?
- jnz end_XY_clip ; no: discard it
-
-
- ;;;;;;;; START OF RIGHT CLIP;;;;;;;;;;;
-
- right_clip:
- mov eax, last_right_vtx
- or eax,eax
- jnz not_first_right
-
- or eax, vtx
- je bottom_clip
-
- mov last_right_vtx,eax ; first vertex
- mov first_right_vtx,eax
- les bx, vtx
- mov eax, es:[bx].NV_xs
- cmp eax, _VS_right4
- jg end_XY_clip
- jmp bottom_clip
-
- not_first_right:
- mov eax, vtx
- or eax,eax
- jnz not_flush_right
-
- les si, first_right_vtx ; flush: test for in-out pair
- mov eax, es:[si].NV_xs
- cmp eax, _VS_right4
- jle pas1b
-
- les di, last_right_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_right4
- jle pas2b
- jmp bottom_clip
- pas1b:
- les di, last_right_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_right4
- jg pas2b
- jmp bottom_clip
-
- pas2b:
- ; nv = x_intercept(first_right_vtx, last_right_vtx, VS_right4);
- ; XY_clip(nv,BOTTOM); /* process this new point */
-
- mov ecx,_VS_right4 ; si,di,es already loaded
- call x_intercept ; create intercept vertex
- push es
- push bx
- call near ptr XY_clip_bottom ; and clip it
- add esp,4
- jmp bottom_clip ; continue to flush
-
- not_flush_right: ; full in-out test
- les si, vtx
- mov eax, es:[si].NV_xs
- cmp eax, _VS_right4
- jle pat1b
-
- les di, last_right_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_right4
- jg no_right_clip
-
- ; nv = x_intercept(vtx, last_right_vtx, VS_right4);
- ; XY_clip(nv,BOTTOM); /* process this new point */
-
- mov ecx,_VS_right4 ; si,di,es already loaded
- call x_intercept ; create intercept vertex
- push es
- push bx
- call near ptr XY_clip_bottom ; and clip it
- add esp,4
-
- no_right_clip:
- mov eax, vtx ; save
- mov last_right_vtx,eax ; was outside, so junk vtx
- jmp end_XY_clip
-
- pat1b: ; in-window test cont'd
- les di, last_right_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_right4
- jle do_right_clip
-
- ; nv = x_intercept(vtx, last_right_vtx, VS_right4);
- ; XY_clip(nv,BOTTOM); /* process this new point */
-
- mov ecx,_VS_right4 ; si,di,es already loaded
- call x_intercept ; create intercept vertex
- push es
- push bx
- call near ptr XY_clip_bottom ; and clip it
- add esp,4
-
- do_right_clip:
- mov eax, vtx ; was in window: continue
- mov last_right_vtx,eax
-
-
- ;;;;;;;; START OF BOTTOM CLIP;;;;;;;;;;;
-
- bottom_clip:
- mov eax, last_bottom_vtx
- or eax,eax
- jnz not_first_bottom
- or eax, vtx
- je left_clip
- mov last_bottom_vtx,eax
- mov first_bottom_vtx,eax
- les bx, vtx
- mov eax, es:[bx].NV_ys
- cmp eax, _VS_bottom4
- jg end_XY_clip
- jmp left_clip
-
- not_first_bottom:
- mov eax, vtx
- or eax,eax
- jnz not_flush_bottom
- les si, first_bottom_vtx
- mov eax, es:[si].NV_ys
- cmp eax, _VS_bottom4
- jle pas1bb
-
- les di, last_bottom_vtx
- mov eax, es:[di].NV_ys
- cmp eax, _VS_bottom4
- jle pas2bb
- jmp left_clip
-
- pas1bb:
- les di, last_bottom_vtx
- mov eax, es:[di].NV_ys
- cmp eax, _VS_bottom4
- jg pas2bb
- jmp left_clip
-
- pas2bb:
- ; nv = y_intercept(first_bottom_vtx, last_bottom_vtx, VS_bottom4);
- ; XY_clip(nv,LEFT); /* process this new point */
-
- mov ecx,_VS_bottom4 ; si,di,es already loaded
- call y_intercept ; create intercept vertex
- push es
- push bx
- call near ptr XY_clip_left ; and clip it
- add esp,4
- jmp left_clip ; continue flush
-
- not_flush_bottom:
- les si, vtx
- mov eax, es:[si].NV_ys
- cmp eax, _VS_bottom4
- jle pat1t
-
- les di, last_bottom_vtx
- mov eax, es:[di].NV_ys
- cmp eax, _VS_bottom4
- jg no_bottom_clip
-
- ; nv = y_intercept(vtx, last_bottom_vtx, VS_bottom4);
- ; XY_clip(nv,LEFT); /* process this new point */
-
- mov ecx,_VS_bottom4 ; si,di,es already loaded
- call y_intercept ; create intercept vertex
- push es
- push bx
- call near ptr XY_clip_left ; and clip it
- add esp,4
-
- no_bottom_clip:
- mov eax, vtx
- mov last_bottom_vtx,eax
- jmp end_XY_clip ; out, so discard it
-
- pat1t:
- les di, last_bottom_vtx
- mov eax, es:[di].NV_ys
- cmp eax, _VS_bottom4
- jle do_bottom_clip
-
- ; nv = y_intercept(vtx, last_bottom_vtx, VS_bottom4);
- ; XY_clip(nv,LEFT); /* process this new point */
-
- mov ecx,_VS_bottom4 ; si,di,es already loaded
- call y_intercept ; create intercept vertex
- push es
- push bx
- call near ptr XY_clip_left ; and clip it
- add esp,4 ; in, so continue
-
- do_bottom_clip:
- mov eax, vtx
- mov last_bottom_vtx,eax
-
-
- ;;;;;;;; START OF LEFT CLIP;;;;;;;;;;;
-
- left_clip:
- mov eax, last_left_vtx
- or eax,eax
- jnz not_first_left
-
- or eax, vtx
- je end_XY_clip
-
- mov last_left_vtx,eax
- mov first_left_vtx,eax
- les bx, vtx
- mov eax, es:[bx].NV_xs
- cmp eax, _VS_left4
- jl end_XY_clip
- jmp do_left_clip
-
- not_first_left:
- mov eax, vtx
- or eax,eax
- jnz not_flush_left
- les si, first_left_vtx
- mov eax, es:[si].NV_xs
- cmp eax, _VS_left4
- jge pas1x
-
- les di, last_left_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_left4
- jge pas2x
- jmp end_XY_clip
-
- pas1x:
- les di, last_left_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_left4
- jge end_XY_clip
-
- pas2x:
- ; nv = x_intercept(first_left_vtx, last_left_vtx, VS_left4);
-
- mov ecx,_VS_left4 ; si,di,es already loaded
- call x_intercept ; create intercept vertex
- mov ax,es ; build far ptr
- shl eax,16
- mov ax,bx
- les di,destptr
- add destptr,4
- mov es:[di],eax ; store new vertex ptr
- inc vtxcount
- jmp end_XY_clip
-
- not_flush_left:
- les si, vtx
- mov eax, es:[si].NV_xs
- cmp eax, _VS_left4
- jge pat1x
-
- les di, last_left_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_left4
- jl no_left_clip
-
- ; nv = x_intercept(vtx, last_left_vtx, VS_left4);
-
- mov ecx,_VS_left4 ; si,di,es already loaded
- call x_intercept ; create intercept vertex
- mov ax,es ; build far ptr
- shl eax,16
- mov ax,bx
- les di,destptr
- add destptr,4
- mov es:[di],eax ; store new vertex ptr
- inc vtxcount
-
- no_left_clip:
- mov eax, vtx
- mov last_left_vtx,eax
- jmp end_XY_clip
-
- pat1x:
- les di, last_left_vtx
- mov eax, es:[di].NV_xs
- cmp eax, _VS_left4
- jge do_left_clip
-
- ; nv = x_intercept(vtx, last_left_vtx, VS_left4);
-
- mov ecx,_VS_left4 ; si,di,es already loaded
- call x_intercept ; create intercept vertex
- mov ax,es ; build far ptr
- shl eax,16
- mov ax,bx
- les di,destptr
- add destptr,4
- mov es:[di],eax ; store new vertex ptr
- inc vtxcount
-
- do_left_clip:
- mov eax, vtx
- mov last_left_vtx,eax
- les di,destptr
- add destptr,4
- mov es:[di],eax ; store new vertex ptr
- inc vtxcount
-
- end_XY_clip:
- mov esp,ebp
- pop ebp
- ret
-
- XY_clip endp
-
-
- end
-
-